package auth

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"errors"
	"io"
	"time"
)

type Auth struct {
	Id             string `json:"keyId"`
	Key            string `json:"key"` //私钥
	Token          string `json:"token"`
	OldToken       string
	updateTokeDate time.Time
	Level          string
}

var Auths []*Auth

func GetVersion() string {
	return "v0.0.3"
}

//创建一个用户的鉴权//返回auth的指针 和 err
func CreateAuth(p_id string, p_k string) (*Auth, error) {
	//确认参数不为空
	if p_id == "" || p_k == "" {
		return nil, errors.New("err: Id or Key is null")
	}
	//看看id是不是已经存在，存在返回报错
	if FindAuthById(p_id) != nil {
		return nil, errors.New("err: Id is existed")
	}
	//创建一个新的结构体
	k := new(Auth)
	k.Id = p_id
	k.Key = p_k
	//将创建好的结构写入数组
	Auths = append(Auths, k)
	//返回信息
	return k, nil
}

//根据id找auth
func FindAuthById(p_id string) *Auth {
	for i, a := range Auths {
		if a.Id == p_id {
			return Auths[i]
		}
	}
	return nil
}

//更新token的函数，//秘钥更新时间不可小于5秒//秘钥失效时间都是 两倍 更新时间
func (k *Auth) UpdateToken(p_time time.Duration) {
	k.updateToken()
	//时间间隔不可小于5秒
	if p_time < 5*time.Second {
		p_time = 5 * time.Second
	}
	ticker := time.NewTicker(p_time) //1 * time.Second
	go func() {
		for range ticker.C {
			// 在这里添加需要执行的任务，自动更新字段
			k.updateToken()
		}
	}()
}

//检查token是否合法，合法返回true不合法返回f
func (k *Auth) ValidateToken() bool {
	a := FindAuthById(k.Key)
	if k.Id == a.Id && (k.Token == a.Token || k.Token == a.OldToken) {
		return true
	}
	return false
}

//func main() {
//	fmt.Println(encryption("UMGG001"))
//}

//字符串加密函数
func encryption(p_str string) (string, error) {
	key := []byte("example-key-1234") // 定义秘钥 //不可改变字符串
	plaintext := []byte(p_str)        // 待加密的数据，可以自定义随机生成

	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil { // 生成随机IV
		return "", err
	}
	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) // CTR模式加密

	//hex.EncodeToString(ciphertext) // 用十六进制打印结果
	return hex.EncodeToString(ciphertext), nil
}

//调用后会更新token将旧的token写入到OldToken
func (k *Auth) updateToken() error {

	if k.Id == "" || k.Key == "" {
		return errors.New("Auto.updateToken Err: Id or Key is null ")
	}
	//获取加密后的key也就是token
	token, err := encryption(k.Key)
	if err != nil {
		return err
	}
	if k.Token == "" { //证明是第一次访问两个token都没有数据
		k.Token = token
		k.OldToken = token
	} else {
		k.OldToken = k.Token
		k.Token = token
	}
	return nil
}
